表单 & Item 事件和 slots 的处理
概述
本节完善表单组件的事件系统(emits)和 expose API,并为 FormItem 添加 slot 支持。通过 defineEmits 定义表单级事件,defineExpose 暴露组件方法,实现完整的表单组件接口。
事件定义(defineEmits)
VForm 事件
// VForm.vue
import type { FormItemProp } from 'element-plus'
interface ValidateCallback {
(isValid: boolean, invalidFields?: Record<string, any>): void
}
const emits = defineEmits<{
(e: 'update:modelValue', value: any): void
(e: 'validate', prop: FormItemProp, isValid: boolean, message: string): void
}>()
// 类型导入注意:FormItemProp 从 element-plus 导入
// import type { FormItemProp } from 'element-plus'
typescript
事件触发
// 表单校验事件
const formRef = ref()
async function validate(props?: FormItemProp[]): Promise<boolean> {
try {
await formRef.value?.validate(props)
return true
} catch (invalidFields) {
// 触发 validate 事件
Object.entries(invalidFields).forEach(([prop, field]) => {
emits('validate', prop, false, field.message)
})
return false
}
}
typescript
Expose API(defineExpose)
使用 exposeEvents 工具函数
// 借鉴 VTable 中使用的 exposeEvents 方法
import { exposeEvents } from '../utils/expose'
const formRef = ref()
// 暴露表单方法
defineExpose(
exposeEvents(formRef, {
validate: () => validate(),
resetFields: () => formRef.value?.resetFields(),
scrollToField: (prop: string) => formRef.value?.scrollToField(prop),
clearValidate: (props?: FormItemProp[]) => formRef.value?.clearValidate(props),
})
)
typescript
FormItem 的 modelValue 定义
// VFormItem.vue
const modelValue = defineModel<any>('modelValue')
// 注意:model 类型应为 any,避免类型冲突
// 单词拼写需准确,错误拼写会导致事件绑定失败
typescript
Slot 支持
FormItem Slot 设计
<!-- VFormItem.vue -->
<template>
<el-form-item :label="item.label" :prop="item.field" :rules="item.rules">
<!-- 默认 slot:自定义表单控件 -->
<slot>
<!-- 默认渲染逻辑 -->
<component :is="componentMap[item.type]" v-model="modelValue" />
</slot>
</el-form-item>
</template>
vue
使用 Slot 自定义表单项
<template>
<VForm :schema="schema" :model="model">
<!-- 通过 slot 覆盖特定字段的渲染 -->
<template #customField="{ item }">
<MyCustomInput v-model="model[item.field]" />
</template>
</VForm>
</template>
vue
完整类型定义
// types/form.ts
export interface FormEmits {
'update:modelValue': [value: Record<string, any>]
'validate': [prop: string, isValid: boolean, message: string]
}
export interface FormExpose {
validate: (props?: string[]) => Promise<boolean>
resetFields: () => void
scrollToField: (prop: string) => void
clearValidate: (props?: string[]) => void
}
typescript
关键要点
defineEmits定义表单的update:modelValue和validate两个核心事件FormItemProp类型需从element-plus正确导入defineExpose暴露validate、resetFields、scrollToField、clearValidate等方法modelValue使用defineModel<any>定义,类型为any避免冲突- Slot 允许用户自定义特定表单项的渲染方式
↑